package my.p2p.client;

import my.p2p.client.util.ByteUtils;
import my.p2p.client.util.ThreadUtils;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;

import static my.p2p.client.ClientToServer.PROP;

/**
 * @author fengbo
 */
public class Client {

    private Socket socket;

    private BufferedInputStream inPunch;
    private BufferedOutputStream outPunch;

    private String fileName;

    void proceedHolePunching(String address, int remotePort, int localPort) {
        ThreadUtils.execute(() -> {
            try {
                socket = new Socket();
                socket.setReuseAddress(true);
                try {
                    socket.bind(new InetSocketAddress(localPort));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                socket.connect(new InetSocketAddress(address, remotePort));
Thread.sleep(10000);
                inPunch = new BufferedInputStream(socket.getInputStream());
                outPunch =  new BufferedOutputStream(socket.getOutputStream());

                while(true) {
                    byte[] buff = read(4);
                    String message = new String(buff, StandardCharsets.UTF_8);
                    System.out.println("message::" + message);

                    if ("AAAA".equals(message)) {
                        long fileLen = ByteUtils.byte2Long(read(8));
System.out.println(fileLen + "=======");
                        File file = new File("D:/im/" + fileName);
                        FileOutputStream outputStream = new FileOutputStream(file);
                        buff = new byte[1024];
                        while (fileLen > 1024) {
                            int read = inPunch.read(buff);
System.out.println(read + "=======");
                            fileLen -= read;
                            outputStream.write(buff, 0, read);
                        }
                        buff = new byte[(int) fileLen];
                        int read = inPunch.read(buff);
                        outputStream.write(buff, 0, read);
                        outputStream.close();

                        continue;
                    }
                    if ("FILE".equals(message)) {
                        long fileLen = ByteUtils.byte2Long(read(8));
                        buff = read((int) fileLen);
                        message = new String(buff, StandardCharsets.UTF_8);
                        File file = new File(message);
                        long len = file.length();
System.out.println(len + "====================");
                        outPunch.write("AAAA".getBytes());
                        outPunch.write(ByteUtils.long2Byte(len));
                        FileInputStream inputStream = new FileInputStream(file);
                        buff = new byte[1024];
                        int read;
                        while ((read = inputStream.read(buff)) > 0) {
                            outPunch.write(buff, 0, read);
                            outPunch.flush();
                        }
                        inputStream.close();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                closeClient();
            }
        });
    }

    void closeClient() {
        try {
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void writeToHole(String msg) throws IOException {
        msg = msg.substring(7);
        String[] fileName = msg.split("/");
        this.fileName = fileName[fileName.length - 1];
        outPunch.write("FILE".getBytes());
        outPunch.write(ByteUtils.long2Byte(Integer.valueOf(msg.getBytes().length).longValue()));
        outPunch.write(msg.getBytes());
        outPunch.flush();
    }

    private void listenPort(int localPort) {
        try{
            ServerSocket serverSocket = new ServerSocket(localPort);
            Socket accept = serverSocket.accept();
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    private byte[] read(int len) throws IOException {
        byte[] buff = new byte[len];
        int off = 0;
        while (len > 0) {
            int read = inPunch.read(buff, off, len);
            len -= read;
            off += read;
        }
        return buff;
    }
}
